using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using LeisureCenter.Api;
using LeisureCenter.Core;

namespace LeisureCenter.Playlist
{
    public abstract class PlaylistMediaItem : BasePlaylistItem
    {
        private int tickCountTotal;
        private int tickCount;

        protected PlaylistMediaItem(BasePlaylist playlist)
            : base(playlist)
        {
        }

        #region tick counting methods

        private void ResetTickCounts()
        {
            tickCount = 0;
            tickCountTotal = 0;
        }

        private void StartTickCount()
        {
            tickCount = Environment.TickCount;
        }

        private void PauseTickCount()
        {
            if (tickCount != 0)
            {
                tickCountTotal += Environment.TickCount - tickCount;
                tickCount = 0;
            }
        }

        private void StopTickCount()
        {
            if (this.tickCount > 0)
            {
                PauseTickCount();
                if ((tickCountTotal / 1000) >= (Duration / 2))
                {
                    played = true;
                    Program.LeisureCenterInstance.libraryManager.playingsLoggerThread.AddFile(Media.FileName);
                }
            }
            ResetTickCounts();
        }

        #endregion

        protected override void PlaylistItem_PlayStateChange(object sender, PlayStateChangeEventArgs e)
        {
            if (e == null)
                return;

            switch (e.NewPlayState)
            {
                case MediaPlayState.Stopped:
                    StopTickCount();
                    break;
                case MediaPlayState.Paused:
                    PauseTickCount();
                    break;
                case MediaPlayState.Playing:
                    StartTickCount();
                    break;
            }
        }

        protected override void PlaylistItem_MediaEnded(object sender, EventArgs e)
        {
            StopTickCount();
            ((MediaPlaylist)_playlist).HandleEndOfMedia();
        }

        public override void Play()
        {
            ResetTickCounts();
            base.Play();
        }
    }

    public class PlaylistFileSystemItem : PlaylistMediaItem
    {
        private FileInfo fileInfo;

        public PlaylistFileSystemItem(BasePlaylist playList, string fileName)
            : base(playList)
        {
            this.fileInfo = new FileInfo(fileName);
        }

        public override string Text
        {
            get { return fileInfo.Name; }
        }

        protected override void CreateMedia()
        {
            Extension ext;
            if (Program.LeisureCenterInstance.Settings.Extensions.TryGetValue(fileInfo.Extension, out ext))
            {
                IPlayer player = Program.LeisureCenterInstance.PlayersManager[ext.Player];
                if (player != null)
                {
                    _media = player.CreateMedia(fileInfo.FullName, ext.Kind);
                }
            }
        }
    }

    public class MediaPlaylist : BasePlaylist
    {
        private IPlaylistItem nextPlaylistItem;
        private Stack<IPlaylistItem> previousItems = new Stack<IPlaylistItem>();

        public MediaPlaylist(PlaylistManager playListManager)
            : base(playListManager)
        {
        }

        internal void HandleEndOfMedia()
        {
            bool wasFullScreen = ActivePlaylistItemOrStub.FullScreen;
            ActivePlaylistItemOrStub.Stop();
            ActivePlaylistItem = nextPlaylistItem;
            if (activePlaylistItem != null)
            {
                activePlaylistItem.Play();
                if (wasFullScreen)
                    activePlaylistItem.FullScreen = true;
            }
            FindNextItem();
        }

        protected void ResetPlayedStatuses()
        {
            foreach (IPlaylistItem item in items)
                item.Played = false;
        }

        private void FindNextItem()
        {
            FindNextItem((playlistManager.PlayMode & PlayMode.Repeat) != 0);
        }

        private void FindNextItem(bool repeatIfNeeded)
        {
            nextPlaylistItem = null;

            if (items.Count == 0)
                return;

            if ((playlistManager.PlayMode & PlayMode.Random) == 0)
            {
                int nextItemIndex = -1;
                if (activePlaylistItem != null)
                    nextItemIndex = activePlaylistItem.Index + 1;
                if (nextItemIndex < 0 || nextItemIndex >= items.Count)
                    nextItemIndex = 0;
                nextPlaylistItem = items[nextItemIndex];
                if (nextPlaylistItem.Played || nextPlaylistItem == activePlaylistItem)
                {
                    if (!repeatIfNeeded)
                        nextPlaylistItem = null;
                    else
                        ResetPlayedStatuses();
                }
            }
            else
            {
                List<IPlaylistItem> unplayedItems = new List<IPlaylistItem>();

                // find the items that haven't been played yet
                foreach (IPlaylistItem playlistItem in items)
                {
                    if (!playlistItem.Played)
                        unplayedItems.Add(playlistItem);
                }

                // if all items have been played but repeat mode is on, start over with all items
                if (unplayedItems.Count == 0 && repeatIfNeeded)
                {
                    ResetPlayedStatuses();
                    unplayedItems.AddRange(items);
                }

                if (unplayedItems.Count > 0)
                {
                    Random rand = new Random();
                    nextPlaylistItem = unplayedItems[rand.Next(unplayedItems.Count)];
                }
            }
            if (nextPlaylistItem != null)
                nextPlaylistItem.Preload();
        }

        protected internal override void playlistManager_PlayModeChanged(object sender, EventArgs e)
        {
            FindNextItem();
        }

        public void AddFileName(string fileName)
        {
            items.Add(new PlaylistFileSystemItem(this, fileName));
            if (this.nextPlaylistItem == null)
                FindNextItem();
        }

        public override void Previous()
        {
            ActivePlaylistItemOrStub.Stop();
            if (previousItems.Count > 0)
            {
                while (!items.Contains(previousItems.Peek()))
                    previousItems.Pop();
                ActivePlaylistItem = previousItems.Peek();
            }
            else
                if (items.Count > 1)
                {

                    base.ActivePlaylistItem = items[(ActivePlaylistItemOrStub.Index + items.Count - 1) % items.Count];
                }
                else
                    return;
            if (activePlaylistItem != null)
                activePlaylistItem.Play();
            FindNextItem(true);
        }

        public override void Next()
        {
            ActivePlaylistItemOrStub.Stop();
            if (nextPlaylistItem == null)
                FindNextItem(true);
            ActivePlaylistItem = nextPlaylistItem;
            if (activePlaylistItem != null)
                activePlaylistItem.Play();
            FindNextItem();
        }

        public override IPlaylistItem ActivePlaylistItem
        {
            get { return base.ActivePlaylistItem; }
            set
            {
                ActivePlaylistItemOrStub.Stop();

                if (previousItems.Count > 0 && previousItems.Peek() == value)
                    previousItems.Pop();
                else
                if (activePlaylistItem != null)
                    previousItems.Push(activePlaylistItem);

                base.ActivePlaylistItem = value;
            }
        }
        
        public override int ActivePlaylistItemIndex
        {
            get
            {
                if (activePlaylistItem != null)
                    return activePlaylistItem.Index;
                else
                    return -1;
            }
            set
            {
                if (value < 0 || value >= items.Count)
                    return;

                ActivePlaylistItem = items[value];
                if (activePlaylistItem != null)
                    activePlaylistItem.Play();
                FindNextItem(true);
            }
        }

        internal void RemoveAllExceptCurrent()
        {
            int index = ActivePlaylistItemIndex;
            if (index > 0)
                this.items.RemoveRange(0, index);
            if (this.items.Count > 1)
                this.items.RemoveRange(1, this.items.Count - 1);
            FindNextItem();
        }

        internal void Remove(int index)
        {
            if (index > -1 && index < this.items.Count && index != ActivePlaylistItemIndex)
            {
                bool findNextAgain = (this.nextPlaylistItem != null) && (this.nextPlaylistItem.Index == index);
                this.items.RemoveAt(index);
                if (findNextAgain)
                    FindNextItem();
            }
        }
    }
}
